package ecweb.service.impl;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.List;

import ecweb.dal.DatabaseSession;
import ecweb.dao.IGoodDao;
import ecweb.dao.IGoodInOrderDao;
import ecweb.dao.IOrderDao;
import ecweb.dao.impl.GoodDao;
import ecweb.dao.impl.GoodInOrderDao;
import ecweb.dao.impl.OrderDao;
import ecweb.domain.GoodInOrder;
import ecweb.domain.GoodItem;
import ecweb.domain.Order;
import ecweb.domain.OrderState;
import ecweb.domain.dto.TGoodInOrderDetail;
import ecweb.domain.dto.TGoodItemAndQuantity;
import ecweb.domain.dto.TOrderDetail;
import ecweb.exception.DatabaseException;
import ecweb.service.IOrderService;
import util.lang.RefValue;

public class OrderService implements IOrderService {
	
	private IOrderDao orderDao=new OrderDao();
	private IGoodInOrderDao goodInOrderDao=new GoodInOrderDao();
	private IGoodDao goodDao=new GoodDao();

	@Override
	public Order getOrderById(long id) throws DatabaseException {

		try (DatabaseSession dbses = new DatabaseSession()) {
			return orderDao.getOrderById(dbses, id);
		}

	}

	@Override
	public List<Order> getOrders(long userIdFilter, OrderState stateFilter,
			long limitStart, long limitLength, RefValue<Long> count)
			throws DatabaseException {
		
		try (DatabaseSession dbses = new DatabaseSession()) {
			
			if (count != null)
				count.setValue(orderDao.getOrdersCount(dbses, userIdFilter, stateFilter));

			List<Order> order=orderDao.getOrders(dbses, userIdFilter, stateFilter, limitStart, limitLength);
			return order;
			}
	}

	private TOrderDetail getOrderDetailInternal(DatabaseSession dbses, Order order) throws DatabaseException {
		List<GoodInOrder> goodInOrder=goodInOrderDao.getGoodInOrderList(dbses, order.getId(), 0, 0, 0);
		LinkedList<TGoodInOrderDetail> goodInOrderDetail=new LinkedList<TGoodInOrderDetail>();
		for(GoodInOrder e:goodInOrder){
			GoodItem goodItem=goodDao.getGoodById(dbses, e.getGoodId());
			TGoodInOrderDetail tGoodInOrderDetail=new TGoodInOrderDetail();
			tGoodInOrderDetail.setGoodItem(goodItem);
			tGoodInOrderDetail.setQuantity(e.getQuantity());
			tGoodInOrderDetail.setTransactionPrice(e.getTransactionPriceEach());
			goodInOrderDetail.add(tGoodInOrderDetail);
		}
		TOrderDetail tOrderDetail=new TOrderDetail();
		tOrderDetail.setOrderInfo(order);
		tOrderDetail.setGoods(goodInOrderDetail);
		return tOrderDetail;
	}
	
	public TOrderDetail getOrderDetailById(long id) throws DatabaseException{
		
		try (DatabaseSession dbses = new DatabaseSession()) {
			return getOrderDetailInternal(dbses,orderDao.getOrderById(dbses, id));
		}
		
	}
	
	@Override
	public List<TOrderDetail> getOrdersDetail(long userIdFilter,
			OrderState stateFilter, long limitStart, long limitLength,
			RefValue<Long> count) throws DatabaseException {
		
		try (DatabaseSession dbses = new DatabaseSession()) {
			if (count != null)
				count.setValue(orderDao.getOrdersCount(dbses, userIdFilter, stateFilter));

			List<Order> order=orderDao.getOrders(dbses, userIdFilter, stateFilter, limitStart, limitLength);
			LinkedList<TOrderDetail> tOrderDetail=new LinkedList<TOrderDetail>();
			for(Order e:order){
				tOrderDetail.add(getOrderDetailInternal(dbses,e));
			}
			return tOrderDetail;
		}
	}

	@Override
	public long getOrdersCount(long userIdFilter, OrderState stateFilter)
			throws DatabaseException {
		
		try (DatabaseSession dbses = new DatabaseSession()) {
			return orderDao.getOrdersCount(dbses, userIdFilter, stateFilter);
		}
	}

	@Override
	public Order createOrder(long userId, List<TGoodItemAndQuantity> goods)
			throws IllegalArgumentException, DatabaseException {
		if (goods.size() == 0)
			throw new IllegalArgumentException();
		try (DatabaseSession dbses = new DatabaseSession(true)) {
			Order order = new Order();
			order.setUserId(userId);
			order.setTransactionPrice(0);
			order.setCreatedDateTime(Timestamp.valueOf(LocalDateTime.now()));
			order.setState(OrderState.NOT_PAYED);
			orderDao.addOrder(dbses, order);
			double sum=0;
			for(TGoodItemAndQuantity e:goods){
				GoodInOrder goodInOrder=new GoodInOrder();
				GoodItem goodItem = goodDao.getGoodById(dbses, e.getGoodId());
				if (e.getQuantity() > goodItem.getInventory())
					e.setQuantity(goodItem.getInventory());
				goodInOrder.setOrderId(order.getId());
				goodInOrder.setGoodId(e.getGoodId());
				goodInOrder.setQuantity(e.getQuantity());
				goodInOrder.setTransactionPriceEach(goodItem.getPrice());
				sum += e.getQuantity()*goodItem.getPrice();
				goodInOrderDao.add(dbses, goodInOrder);
				goodItem.setInventory(goodItem.getInventory() - e.getQuantity());
				goodDao.updateGoodById(dbses, goodItem);
			}
			order.setTransactionPrice(sum);
			orderDao.updateOrderById(dbses, order);
			
			if (!dbses.tryCommit()) {
				dbses.rollback();
			}
			
			return order;
			
		}
		
	}

	@Override
	public void removeOrder(long orderId) throws IllegalArgumentException, DatabaseException {
		try (DatabaseSession dbses = new DatabaseSession(true)) {
			Order order = orderDao.getOrderById(dbses, orderId);
			if(order == null)
				throw new IllegalArgumentException();
			if(order.getState().getCode() == OrderState.NOT_PAYED.getCode()){
				TOrderDetail tOrderDetail = getOrderDetailInternal(dbses,order);
				for(TGoodInOrderDetail tGoodInOrderDetail:tOrderDetail.getGoods()){
					GoodItem goodItem = tGoodInOrderDetail.getGoodItem();
					goodItem.setInventory(tGoodInOrderDetail.getQuantity()+goodItem.getInventory());
					goodDao.updateGoodById(dbses, goodItem);
				}
			}
			orderDao.deleteOrderById(dbses, orderId);
			
			if (!dbses.tryCommit()) {
				dbses.rollback();
			}
			
		}
	}
}
